<?php
apf_require_class("APF_Controller");

class APF_Resource_ResourcesController extends APF_Controller {
    const CONFIG_F_RESOURCE = 'resource';
    const CONFIG_N_VERSION = 'version';
    const CONFIG_N_PREFIX_URI = 'prefix_uri';
    const CONFIG_N_RESOURCE_TYPE_SINGLE = 'resource_type_single';
    const CONFIG_N_RESOURCE_TYPE_BOUNDABLE = 'resource_type_boundable';

    const DEFAULT_PREFIX_URI = 'res';
    const DEFAULT_RESOURCE_TYPE_SINGLE = 's';
    const DEFAULT_RESOURCE_TYPE_BOUNDABLE = 'b';

    const CONFIG_N_MATCH_IDX_TYPE = "match_type";
    const CONFIG_N_MATCH_IDX_FILE = "match_file";
    const CONFIG_N_MATCH_IDX_EXT  = "match_ext";

    const DEFAILT_MATCH_IDX_TYPE = 1;
    const DEFAILT_MATCH_IDX_FILE = 2;
    const DEFAILT_MATCH_IDX_EXT  = 3;

/**
     * Returns the uri of single resource
     *
     * @param string $resource full name of the resource
     * @return string
     */
    public static function build_uri($resource) {
        if (preg_match('/:\/\//', $resource)) {
            // is external resource
            return $resource;
        }
        $apf = APF::get_instance();
        $version = @$apf->get_config(self::CONFIG_N_VERSION, self::CONFIG_F_RESOURCE);
        $prefix = @$apf->get_config(self::CONFIG_N_PREFIX_URI, self::CONFIG_F_RESOURCE);
        if (!isset($prefix)) {
            trigger_error("Unable to get config \"".self::CONFIG_N_PREFIX_URI."\" from \"".self::CONFIG_F_RESOURCE."\"", E_USER_NOTICE);
            $prefix = self::DEFAULT_PREFIX_URI;
        }
        $type = @$apf->get_config(self::CONFIG_N_RESOURCE_TYPE_SINGLE, self::CONFIG_F_RESOURCE);
        if (!isset($type)) {
            trigger_error("Unable to get config \"".self::CONFIG_N_RESOURCE_TYPE_SINGLE."\" from \"".self::CONFIG_F_RESOURCE."\"", E_USER_NOTICE);
            $type = self::DEFAULT_RESOURCE_TYPE_SINGLE;
        }

        if (isset($version)) {
            return "$prefix/$version/$type/$resource";
        } else {
            return "$prefix/$type/$resource";
        }
    }

    /**
     * Returns the uri of boundable resource
     *
     * @param string $resource Page name
     * @param string $ext File extention without prefix dot
     * @return string
     */
    public static function build_boundable_uri($resource, $ext) {
        $apf = APF::get_instance();
        $version = @$apf->get_config(self::CONFIG_N_VERSION, self::CONFIG_F_RESOURCE);
        $prefix = @$apf->get_config(self::CONFIG_N_PREFIX_URI, self::CONFIG_F_RESOURCE);
        if (!isset($prefix)) {
            trigger_error("Unable to get config \"".self::CONFIG_N_PREFIX_URI."\" from \"".self::CONFIG_F_RESOURCE."\"", E_USER_ERROR);
        }
        $type = $apf->get_config(self::CONFIG_N_RESOURCE_TYPE_BOUNDABLE, self::CONFIG_F_RESOURCE);
        if (!isset($type)) {
            trigger_error("Unable to get config \"".self::CONFIG_N_RESOURCE_TYPE_BOUNDABLE."\" from \"".self::CONFIG_F_RESOURCE."\"", E_USER_ERROR);
        }

        if (isset($version)) {
            return "$prefix/$version/$type/$resource.$ext";
        } else {
            return "$prefix/$type/$resource.$ext";
        }
    }

    public function handle_request() {
        $apf = APF::get_instance();

        // TODO:use better debug output method
        $request = $apf->get_request();
        $response = $apf->get_response();

        $matches = $request->get_router_matches();

        // TODO: get indexes from config
        $idx_type = self::DEFAILT_MATCH_IDX_TYPE;
        $idx_file = self::DEFAILT_MATCH_IDX_FILE;
        $idx_ext = self::DEFAILT_MATCH_IDX_EXT;

        $type = $matches[$idx_type];
        $file = $matches[$idx_file];
        $ext = $matches[$idx_ext];

        if ($ext == 'css') {
            $content_type = "text/css";
        } elseif ($ext == 'js') {
           $content_type = "application/x-javascript";
        } else {
            trigger_error("Unknown extention \"$ext\"", E_USER_ERROR);
            return;
        }
        $response->set_content_type($content_type);

        if ($this->try304()) {
            return;
        };

        // TODO: get types form config
        $type_single = self::DEFAULT_RESOURCE_TYPE_SINGLE;
        $type_boundable = self::DEFAULT_RESOURCE_TYPE_BOUNDABLE;

        if ($type == $type_boundable) {
            $this->fetch_boundable_resources($file, $ext, TRUE);
            $this->passthru_boundable_resources();
        } elseif ($type == $type_single) {
            if (!$this->include_resource_file("$file.$ext")) {
                trigger_error("Unable to include resource \"$file.$ext\"", E_USER_WARNING);
            }
        }
    }

    protected function fetch_boundable_resources($class, $ext, $is_page=false) {
        if ($is_page) {
            apf_require_page($class);
            $path =  "page/";
            $class = $class."Page";
        } else {
            apf_require_component($class);
            $path =  "component/";
            $class = $class."Component";
        }

        eval("\$list = $class"."::use_component();");
        foreach ($list as $item) {
            $this->fetch_boundable_resources($item, $ext);
        }

        if ($ext == 'js') {
            eval("\$list = $class::use_boundable_javascripts();");
        } elseif ($ext == 'css') {
            eval("\$list = $class::use_boundable_styles();");
        } else {
            trigger_error("Unknown extention \"$ext\"", E_USER_WARNING);
            $list = array();
        }

        $apf = APF::get_instance();
        foreach($list as $item) {
            $apf->prcess_resource_url($path, $item, $this->boundable_resources);
        }

            //if (!$this->include_resource_file($item[0])) {
            //    trigger_error("Unable to include resource \"".$item[0]."\"", E_USER_WARNING);
            //}
    }

    protected function passthru_boundable_resources() {
        if ($this->boundable_resources) {
            usort($this->boundable_resources, "APF::resource_order_comparator");
        }
        foreach ($this->boundable_resources as $item) {
            if (!$this->include_resource_file($item[0])) {
                trigger_error("Unable to include resource \"".$item[0]."\"", E_USER_WARNING);
            }
        }
    }

    private $boundable_resources;

    protected function include_resource_file($file, $path=NULL) {
        if (isset($path)) {
            if (file_exists($path.$file)) {
                include_once($path.$file);
                return true;
            }
        } else {
            global $G_LOAD_PATH;
            foreach ($G_LOAD_PATH as $path) {
                if (file_exists($path.$file)) {
                    include_once($path.$file);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     *
     * @return boolean
     */
    protected function try304() {
        if (!defined("RELEASE_VERSION")) {
            return false;
        }

        $apf = APF::get_instance();
        $response = $apf->get_response();

        $last_modified = strtotime("2009-06-04 00:00:00");

        if (isset($last_modified)) {
            $etag = '"'.dechex($last_modified).'"';
        }

        if (isset($etag)) {
            $none_match = @$_SERVER['HTTP_IF_NONE_MATCH'];
            if ($none_match && $none_match == $etag) {
                $response->set_header("HTTP/1.1", "304 ETag Matched", "304");
                return true;
            }
        }

        if (isset($last_modified) && isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
            $tmp = explode(";", $_SERVER['HTTP_IF_MODIFIED_SINCE']);
            $modified_since = @strtotime($tmp[0]);
            if ($modified_since && $modified_since >= $last_modified) {
                $response->set_header("HTTP/1.1", "304 Not Modified", "304");
                return true;
            }
        }

        if (isset($last_modified)) {
            $response->set_header("ETag", $etag);
            $response->set_header("Last-Modified", gmdate("D, d M Y H:i:s", $last_modified) . " GMT");
        }

        return false;
    }
}
